﻿namespace Rage.Base.Abilities
{
    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;

    public class AbilityWrapper
    {
        public AbilityWrapper(ClassAbility ability)
        {
            Ability = ability;
            _isDamaging = Ability.DamageOverride + Ability.DamageOnUseOverride > 0f;
        }
        public ClassAbility Ability { get; set; }
        protected bool _isDamaging = false;
        public bool IsDamaging { get { return _isDamaging; } protected set { _isDamaging = value; } }
        // Opener
        private float _numActivatesOpener = 0f;
        public float NumActivatesOpener
        {
            get { return _numActivatesOpener; }
            set { if (_numActivatesOpener != value) { _numActivatesOpener = value; gcdUsageOpener = -1f; } }
        }
        public float ResourceOpener { get { return Ability.ResourceCost == -1 ? 0f : Ability.GetResourceUseOverDur(NumActivatesOpener); } }
        private float _openerTotalTime = -1f;
        public float OpenerTotalTime
        {
            get
            {
                if (_openerTotalTime == -1f) {
                    _openerTotalTime = 0.00f;
                }
                return _openerTotalTime;
            }
            set { _openerTotalTime = value; }
        }
        public float DPS_Opener { get { return OpenerTotalTime == 0 || Ability.FightDuration == 0 ? 0 : Ability.GetDPS(NumActivatesOpener, OpenerTotalTime / Ability.FightDuration); } }
        public float TPS_Opener { get { return OpenerTotalTime == 0 || Ability.FightDuration == 0 ? 0 : Ability.GetTPS(NumActivatesOpener, OpenerTotalTime / Ability.FightDuration); } }
        public float HPS_Opener { get { return OpenerTotalTime == 0 || Ability.FightDuration == 0 ? 0 : Ability.GetHPS(NumActivatesOpener, OpenerTotalTime / Ability.FightDuration); } }
        private float gcdUsageOpener = -1f;
        public float GCDUsageOpener
        {
            get
            {
                if (gcdUsageOpener == -1f && Ability.UsesGCD)
                {
                    gcdUsageOpener = NumActivatesOpener * (Ability.UseTime / LatentGCD);
                }
                return gcdUsageOpener;
            }
        }
        // Over 20%
        private float _numActivatesO20 = 0f;
        public float NumActivatesO20
        {
            get { return _numActivatesO20; }
            set { if (_numActivatesO20 != value) { _numActivatesO20 = value; gcdUsageO20 = -1f; } }
        }
        public float ResourceO20 { get { return Ability.ResourceCost == -1 ? 0f : Ability.GetResourceUseOverDur(NumActivatesO20); } }
        public float DPS_O20 { get { return Ability.GetDPS(NumActivatesO20, Ability.TimeOver20Perc - OpenerTotalTime / Ability.FightDuration); } }
        public float TPS_O20 { get { return Ability.GetTPS(NumActivatesO20, Ability.TimeOver20Perc - OpenerTotalTime / Ability.FightDuration); } }
        public float HPS_O20 { get { return Ability.GetHPS(NumActivatesO20, Ability.TimeOver20Perc - OpenerTotalTime / Ability.FightDuration); } }
        private float gcdUsageO20 = -1f;
        public float GCDUsageO20
        {
            get
            {
                if (gcdUsageO20 == -1f && Ability.UsesGCD)
                {
                    gcdUsageO20 = NumActivatesO20 * (Ability.UseTime / LatentGCD);
                }
                return gcdUsageO20;
            }
        }
        // Under 20%
        private float _numActivatesU20 = 0f;
        public float NumActivatesU20
        {
            get { return _numActivatesU20; }
            set { if (_numActivatesU20 != value) { _numActivatesU20 = value; gcdUsageU20 = -1f; } }
        }
        public float ResourceU20 { get { return Ability.ResourceCost == -1 ? 0f : Ability.GetResourceUseOverDur(NumActivatesU20); } }
        public float DPS_U20 { get { return Ability.GetDPS(NumActivatesU20, Ability.TimeUndr20Perc); } }
        public float TPS_U20 { get { return Ability.GetTPS(NumActivatesU20, Ability.TimeUndr20Perc); } }
        public float HPS_U20 { get { return Ability.GetHPS(NumActivatesU20, Ability.TimeUndr20Perc); } }
        private float gcdUsageU20 = -1f;
        public float GCDUsageU20
        {
            get
            {
                if (gcdUsageU20 == -1f && Ability.UsesGCD)
                {
                    gcdUsageU20 = NumActivatesU20 * (Ability.UseTime / LatentGCD);
                }
                return gcdUsageU20;
            }
        }
        private static float _cachedLatentGCD = 1.5f;
        public static float LatentGCD { get { return _cachedLatentGCD; } set { _cachedLatentGCD = value; } }
        // Total
        public float AllNumActivates { get { return NumActivatesOpener + NumActivatesO20 + NumActivatesU20; } }
        public float AllResource { get { return ResourceOpener + ResourceO20 + ResourceU20; } }
        public float AllDPS
        {
            get
            {
                float dpsOpener = DPS_Opener;
                float dpsO20 = DPS_O20;
                float dpsU20 = DPS_U20;
                float openerPerc = OpenerTotalTime == 0 || Ability.FightDuration == 0 ? 0 : (OpenerTotalTime / Ability.FightDuration);
                return dpsOpener * openerPerc + dpsO20 * (Ability.TimeOver20Perc - openerPerc) + dpsU20 * Ability.TimeUndr20Perc;
            }
        }
        public float AllTPS
        {
            get
            {
                float tpsOpener = TPS_Opener;
                float tpsO20 = TPS_O20;
                float tpsU20 = TPS_U20;
                float openerPerc = OpenerTotalTime == 0 || Ability.FightDuration == 0 ? 0 : (OpenerTotalTime / Ability.FightDuration);
                return tpsOpener * openerPerc + tpsO20 * (Ability.TimeOver20Perc - openerPerc) + tpsU20 * Ability.TimeUndr20Perc;
            }
        }
        public float AllHPS
        {
            get
            {
                float hpsOpener = HPS_Opener;
                float hpsO20 = HPS_O20;
                float hpsU20 = HPS_U20;
                float openerPerc = OpenerTotalTime == 0 || Ability.FightDuration == 0 ? 0 : (OpenerTotalTime / Ability.FightDuration);
                return hpsOpener * openerPerc + hpsO20 * (Ability.TimeOver20Perc - openerPerc) + hpsU20 * Ability.TimeUndr20Perc;
            }
        }

        public override string ToString()
        {
            if (Ability == null) return "NULLed";
            return string.Format("{0} : Resource {1:0.##} : DPS {2:0.##} : HPS {3:0.##} : TPS {4:0.##}",
                Ability.Name, AllResource == 0 ? "<None>" : string.Format("{0:0.##}", AllResource), AllDPS, AllHPS, AllTPS);
        }
    }
}
